package com.aliwo.reflect;

import com.aliwo.Cat;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ClassTest {

    public static void main(String[] args) throws Exception {
        // 第一种获取类对象
        Class<Cat> catClass1 = Cat.class;
        // 第二种获取类对象
        Cat cat = new Cat();
        Class<? extends Cat> aClass = cat.getClass();
        // 第三种获取类对象
        Class<?> aClass1 = null;
        try {
            aClass1 = Class.forName("com.aliwo.Cat");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        // 第四种获取类对象 通过类加载器
        ClassLoader classLoader = ClassTest.class.getClassLoader();
        Class<?> aClass2 = classLoader.loadClass("com.aliwo.Cat");
        System.out.println(".class获取类对象" + catClass1);
        System.out.println("getClass获取类对象" + aClass);
        System.out.println("Class.forNam获取类对象" + aClass1);
        System.out.println("通过类加载器获取类对象" + aClass2);

        System.out.println("获取名称 包名 + 类名：" + catClass1.getName());
        System.out.println("获取名称 类名：" + catClass1.getSimpleName());

        // 获取声明的构造方法（包含共有和私有构造方法）
        Constructor<?>[] declaredConstructors = catClass1.getDeclaredConstructors();
        for (Constructor c : declaredConstructors) {
            System.out.println(c.getName() + "," + Arrays.toString(c.getParameterTypes()) + "," + Arrays.toString(c.getParameters()));
        }

        // 通过无参构造函数创建对象实例
        Constructor<Cat> declaredConstructor = catClass1.getDeclaredConstructor();
        Cat cat1 = declaredConstructor.newInstance();
        cat1.setAge(1);
        cat1.setName("xyy");
        System.out.println("cat1:" + cat1);

        Cat cat2 = catClass1.newInstance();
        cat2.setAge(2);
        cat2.setName("xy2");
        System.out.println("cat2:" + cat2);

        // 通过指定构造器 创建对象实例
        Constructor<Cat> declaredConstructor1 = catClass1.getDeclaredConstructor(String.class);
        Cat cat3 = declaredConstructor1.newInstance("有参用户名");
        System.out.println("cat3:" + cat3);

        // 通过指定构造器 创建对象实例 类必须提供有参的构造器和public权限，否则创建失败
        // Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
        //	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        //	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        //	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        //	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        //	at com.aliwo.reflect.ClassTest.main(ClassTest.java:58)
        Constructor<Cat> declaredConstructor2 = catClass1.getDeclaredConstructor(String.class, String.class);
//        Cat cat4 = declaredConstructor1.newInstance("有参用户名", "有参密码");
//        System.out.println("cat4:" + cat4);

        // 通过反射获取方法
        // 通过反射获取当前运行类和父类声明中的方法，需要是public访问权限的方法
        Method[] methods = catClass1.getMethods();
        for (Method m : methods) {
            System.out.println("获取全部的返回值类型：" + m.getReturnType().getName() + "," + "获取全部的参数类型 +" + Arrays.toString(m.getParameterTypes()) + "," + "获取修饰符类型：" + m.getModifiers());
        }

        System.out.println("=======================");
        // 通过反射获取当前运行类中声明的全部方法，不包含父类中声明的方法
        Method[] declaredMethods = catClass1.getDeclaredMethods();
        for (Method m : declaredMethods) {
            System.out.println("获取全部的返回值类型：" + m.getReturnType().getName() + "," + "获取全部的参数类型 +" + Arrays.toString(m.getParameterTypes()) + "," + "获取修饰符类型：" + m.getModifiers());
        }

        // 通过反射获取属性
        // 通过反射获取当前运行类和父类声明中的全部属性，需要是public访问权限的方法
        Field[] fields = catClass1.getFields();
        for (Field f : fields) {
            System.out.println("获取全部的返回值类型：" + f.getName() + "," + "获取修饰符类型：" + f.getModifiers());
        }

        System.out.println("=======================");
        // 通过反射获取当前运行类中声明的全部属性，不包含父类中声明的方法
        Field[] declaredFields = catClass1.getDeclaredFields();
        for (Field m : declaredFields) {
            System.out.println("获取全部的返回值类型：" + m.getName() + ","+ "获取修饰符类型：" + m.getModifiers());
        }

        Cat cat4 = catClass1.newInstance();
        Field name = catClass1.getDeclaredField("name");
        name.setAccessible(true);
        name.set(cat4, "暴力破解 private修饰的属性");
        System.out.println("暴力破解 name的值:"+name.get(cat4));

        Method declaredMethod = catClass1.getDeclaredMethod("hi2", String.class);
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(cat4, "反射用户信息");

        Method declaredMethod1 = catClass1.getDeclaredMethod("hi3", String.class, String.class);
        declaredMethod1.setAccessible(true);
        declaredMethod1.invoke(null, "反射调用静态方法用户名", "反射调用静态方法密码");
    }
}
